package blackstar.plugin.ui;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import blackstar.agent.AgentConfig;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

/**
 * @author RayWoo (ayufox@gmail.com)
 * 
 */
public class MonitorServlet extends HttpServlet
{
	private final static Log LOGGER = LogFactory.getLog(MonitorServlet.class);

	private String dataPath = AgentConfig.getDataPath();

	protected void service(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException
	{
		String uri = request.getRequestURI();
		if (!"/".equals(request.getContextPath()))
		{
			uri = uri.substring(request.getContextPath().length());
		}
		LOGGER.info("request:" + uri);
		String[] pathArray = uri.substring(1).split("/");
		if (pathArray.length == 1)
		{
			LOGGER.info("Error Request Path:" + uri);
			response.sendError(404);
		} else if (pathArray.length == 2)
		{
			printTime(request, response, pathArray[1]);
		} else if (pathArray.length == 4)
		{
			printMonitorChart(request, response, uri, pathArray);
		} else
		{
			LOGGER.info("Error Request Path:" + uri);
			response.sendError(404);
		}
	}

	private void printTime(HttpServletRequest request,
			HttpServletResponse response, String jvmid) throws IOException
	{
		File dir = new File(dataPath + "/" + jvmid + "/monitor");

		LOGGER.info("list [" + dir.getAbsolutePath() + "]");

		if (dir.exists())
		{
			File[] list = dir.listFiles();
			List<String> dates = new ArrayList<String>();// 日期
			for (File f : list)
			{
				dates.add(f.getName());
			}
			Collections.sort(dates, new Comparator<String>()
			{
				public int compare(String o1, String o2)
				{
					return o2.compareTo(o1);
				}
			});

			PrintWriter writer = response.getWriter();

			SimpleDateFormat srcFormat = new SimpleDateFormat("yyyyMMdd");
			SimpleDateFormat targetFormat = new SimpleDateFormat("yyyy-MM-dd");

			writer.print("[");
			int index = 0;
			for (String date : dates)
			{
				if (index > 0)
				{
					writer.print(",");
				}
				writer.print("{");
				writer.print("value :'");
				writer.print(date);
				writer.print("', text :'");
				try
				{
					writer.print(targetFormat.format(srcFormat.parse(date)));
				} catch (Exception e)
				{
					writer.print(date);
				}
				writer.print("'}");
				index++;
			}
			writer.print("]");
			writer.flush();
		} else
		{
			LOGGER.info("dir [" + dir.getAbsolutePath() + "] not exists");
			response.sendError(404);
		}

	}

	private void printMonitorChart(HttpServletRequest request,
			HttpServletResponse response, String uri, String[] pathArray)
			throws IOException
	{
		String jvmid = pathArray[1];
		String date = pathArray[2];
		String monitortype = pathArray[3];
		LOGGER.info("jvmid[" + jvmid + "], date[" + date + "], monitortye["
				+ monitortype + "]");
		File dataFile = new File(dataPath + "/" + jvmid + "/monitor/" + date
				+ "/" + monitortype);
		LOGGER.info("dataFile[" + dataFile.getAbsolutePath() + "]");

		if (dataFile.exists())
		{
			try
			{
				SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
				Date queryDate = format.parse(date);
				Calendar calendar = Calendar.getInstance();
				calendar.setTime(queryDate);
				calendar.add(Calendar.DAY_OF_MONTH, -1);

				Date preDate = calendar.getTime();

				SimpleDateFormat printDateFormat = new SimpleDateFormat(
						"yyyy-MM-dd");

				File preDataFile = new File(dataPath + "/" + jvmid
						+ "/monitor/" + format.format(preDate) + "/"
						+ monitortype);

				Map root = new HashMap();
				root.put("requestContext", request.getContextPath());
				root.put("jvmid", pathArray[0]);
				root.put("monitortype", monitortype);
				root.put("preday", printDateFormat.format(preDate));
				root.put("queryday", printDateFormat.format(queryDate));
				if ("cpu".equalsIgnoreCase(monitortype))
				{
					root.put("unit", "Percent (%)");
				} else if ("thread".equals(monitortype))
				{
					root.put("unit", "Number");
				} else
				{
					root.put("unit", "M");
				}
				root.put("predaydata", parseData(preDataFile, monitortype));
				root.put("querydayData", parseData(dataFile, monitortype));

				PrintWriter writer = response.getWriter();

				Configuration cfg = new Configuration();
				cfg.setClassForTemplateLoading(MonitorServlet.class,
						"/template");
				cfg.setObjectWrapper(new DefaultObjectWrapper());

				Template temp = cfg.getTemplate("monitor.html");

				temp.process(root, writer);
				writer.flush();
			} catch (Exception e)
			{
				LOGGER.error("error when read data files", e);

				response.sendError(505);
			}
		} else
		{
			LOGGER.info("DataPath Not Exist:" + uri);
			response.sendError(404);
		}
	}

	private String parseData(File dataFile, String monitorType)
			throws IOException
	{
		if (!dataFile.exists())
		{
			return "";
		}

		BufferedReader reader = new BufferedReader(new FileReader(dataFile));
		String line = null;
		List<Integer> datas = new ArrayList<Integer>();
		String[] values = new String[24 * 12];
		int hour = 0;
		int minute = 0;
		while ((line = reader.readLine()) != null)
		{
			String[] array = line.split("\\|");
			hour = new Integer(array[0].substring(8, 10));// 小时
			minute = new Integer(array[0].substring(10, 12));// 分钟
			int value = new Integer(array[1]);
			datas.add(value);
			if (minute % 5 == 4)
			{
				int data = Collections.max(datas);
				int index = hour * 12 + minute / 5;
				if ("cpu".equals(monitorType))
				{
					values[index] = Float.toString(((float) data / 10));
				} else
				{
					values[index] = Integer.toString(data);
				}
				datas.clear();
			}
		}

		if (datas.size() > 0)
		{
			int data = Collections.max(datas);
			int index = hour * 12 + minute / 5;
			if ("cpu".equals(monitorType))
			{
				values[index] = Float.toString(((float) data / 10));
			} else
			{
				values[index] = Integer.toString(data);
			}
		}

		StringBuffer buffer = new StringBuffer();
		int index = 0;
		for (int i = values.length - 1; i >= 0; i--)
		{
			if (values[i] != null)
			{
				index = i;
				break;
			}
		}
		for (int i = 0; i <= index; i++)
		{
			if (i > 0)
			{
				buffer.append(",");
			}

			if (values[i] == null)
			{
				buffer.append("0");
			} else
			{
				buffer.append(values[i]);
			}
		}

		return buffer.toString();
	}
}